package com.coldlz.mmp.proxy.handlerclient;

import com.coldlz.mmp.proxy.*;
import io.netty.channel.*;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.*;
import io.netty.handler.codec.http.websocketx.*;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Slf4j
public class ClientChannelInitializer extends ChannelInitializer<SocketChannel> {
    private final UserContext userContext;

    public ClientChannelInitializer(UserContext userContext) {
        this.userContext = userContext;
    }

    @Override
    protected void initChannel(SocketChannel ch) throws Exception {
        // 这里必须不对pipeline进行初始化，因为后面才能够确定是ws协议还是http协议
    }

    public void reinitializeChannel(Channel ch) {
        ChannelPipeline pipeline = ch.pipeline();
        List<ChannelHandler> removes = new ArrayList<>();
        for (Map.Entry<String, ChannelHandler> entry : pipeline) {
            ChannelHandler value = entry.getValue();
            if (!value.getClass().getPackageName().startsWith("io.netty")) {
                removes.add(value);
            }
        }
        for (ChannelHandler handler : removes) {
            pipeline.remove(handler);
        }

        ProxyInfo info = userContext.getProxyInfo();
        if (userContext.isDirectForward()) {
            ch.pipeline().addLast(new ClientProxyHttpHandler(userContext));
        } else {
            Protocol protocolName = info.getProtocolName();
            if (protocolName == Protocol.WSS || protocolName == Protocol.HTTPS) {
                ch.pipeline().addLast(SslContextManager.getClientSsl().newHandler(ch.alloc()));
            }


            if (protocolName == Protocol.WS || protocolName == Protocol.WSS) {
                int maxPayload = 65535;
                ch.pipeline().addLast(new HttpClientCodec());
                ch.pipeline().addLast(new HttpObjectAggregator(maxPayload));
                ch.pipeline().addLast(new ClientPeekMessageHandler(userContext));


                HttpHeaders defHeaders = new DefaultHttpHeaders();
                for (Header header : info.getWebSocketHttpHeaders()) {
                    defHeaders.add(header.key, header.value);
                }
                WebSocketClientProtocolConfig config = WebSocketClientProtocolConfig.newBuilder()
                        .webSocketUri(info.getWebSocketURI())
                        .version(info.getWebSocketVersion())
                        .allowExtensions(true)
                        .allowMaskMismatch(true)
                        .withUTF8Validator(true)
                        .maxFramePayloadLength(maxPayload)
                        .customHeaders(defHeaders)
                        .handshakeTimeoutMillis(5000)
                        .build();
                WebSocketClientProtocolHandler webSocketClientProtocolHandler = new WebSocketClientProtocolHandler(config);
                WebSocketClientHandshaker handshaker = webSocketClientProtocolHandler.handshaker();
                ch.pipeline().addLast(webSocketClientProtocolHandler);

                // WebSocketClientProtocolHandshakeHandler


//                WebSocketFrameDecoder decoder = new WebSocket13FrameDecoder(WebSocketDecoderConfig
//                        .newBuilder()
//                        .allowExtensions(true)
//                        .allowMaskMismatch(true)
//                        .withUTF8Validator(true)
//                        .build());
//                WebSocketFrameEncoder encoder = new WebSocket13FrameEncoder(true);
//                ch.pipeline().addLast(decoder);
//                ch.pipeline().addLast(encoder);


//                WebSocketFrameEncoder webSocketFrameEncoder = switch (info.getWebSocketVersion()) {
//                    case V13 -> new WebSocket13FrameEncoder(true);
//                    case V08 -> new WebSocket08FrameEncoder(true);
//                    case V07 -> new WebSocket07FrameEncoder(true);
//                    case V00 -> new WebSocket00FrameEncoder();
//                    default -> throw new RuntimeException("不支持的 WebSocket 版本");
//                };
//                ch.pipeline().addLast(webSocketFrameEncoder);
            } else {
                ch.pipeline().addLast(new HttpClientCodec());
            }

            if (protocolName == Protocol.WS || protocolName == Protocol.WSS) {
                ch.pipeline().addLast(new ClientProxyWsHandler(userContext));

                // io.netty.handler.codec.http.websocketx.WebSocketClientProtocolHandshakeHandler
//                ChannelHandlerContext context = ch.pipeline().context("io.netty.handler.codec.http.websocketx.WebSocketClientProtocolHandshakeHandler");
//                ch.pipeline().context("io.netty.handler.codec.http.websocketx.WebSocketClientProtocolHandshakeHandler");
//                context.fireChannelActive();
            } else if (protocolName == Protocol.HTTP || protocolName == Protocol.HTTPS) {
                ch.pipeline().addLast(new ClientProxyHttpHandler(userContext));
            } else {
                throw new RuntimeException("参数异常");
            }
        }
    }
}
